package weeny.delaunay;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import delaunay.DelaunayTriangulation;
import delaunay.Simplex;
import delaunay.Vertex;

public abstract class AbstractDelaunayUtil {
	/**
	 * Give a Point2D "View" of the node object.
	 */
	protected abstract Point2D asPnt(Object node);

	/**
	 * This function give you a set of triangles, the return type is a set of
	 * sets, every inner set contains three elements representing three points
	 * of a triangle, the node positions are decided by {@link #asPnt(Object)}
	 */
	public Set<Set> delaunay(Iterator iter){
		Set<Vertex> nodeSet = new HashSet<Vertex>();
		Rectangle2D rect = null;//contains all nodes
		while (iter.hasNext()){
			Object node = iter.next();
			Point2D pt = asPnt(node);
			if (rect == null) {
				rect = new Rectangle2D.Double(pt.getX(),pt.getY(),0,0);
			}
			else{
				rect.add(pt);
			}
			Vertex ver = new Vertex(pt.getX(), pt.getY());
			ver.setID(node);
			nodeSet.add(ver);
		}
		//if it is not enough to form a triangle
		if (nodeSet.size()<3) {
			return null;
		}
		//expand the rect
		rect.add(rect.getMinX()-100, rect.getMinY()-100);
		rect.add(rect.getMaxX()+100, rect.getMaxY()+100);
		
		//init with a triangle containing all nodes
		//these three boundary nodes have id = null
		Simplex<Vertex> simplex = new Simplex<Vertex>(
				new Vertex(rect.getMinX()-rect.getHeight(), rect.getMinY()),
				new Vertex(rect.getMaxX()+rect.getHeight(), rect.getMinY()),
				new Vertex(rect.getCenterX(), rect.getMaxY()+rect.getWidth()/2)
				);
		DelaunayTriangulation dt = new DelaunayTriangulation(simplex);
		for (Vertex ver : nodeSet){
			dt.delaunayPlace(ver);
		}
		Set<Set> resultTris = new HashSet<Set>();
		for (Simplex<Vertex> tri : dt) { 
        	Set set = new HashSet();
        	for (Set<Vertex> edge: tri.facets()) {
        		for (Vertex vertex : edge) {
					set.add(vertex.getID());
				}
        	}
        	//if it contains one of the boundary nodes, skip it
        	if (set.contains(null)) {
				continue;
			}
       		resultTris.add(set);	
        }//done for every tri in the dt
		return resultTris;
	}
}
